﻿//-----------------------------------------------------------------------
// <copyright file="CharacterRepositoryTest.cs" company="FastNET Services">
//     Copyright (c) 2008-2009. All Rights Reserved.
// </copyright>
// <license>
//     GPLv2
// </license>
// <warranty>
//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
//     BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//     DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </warranty>
//-----------------------------------------------------------------------
#region Usings

using System;
using System.Collections.Generic;
using System.Data.EntityClient;
using System.Linq;
using GateShift.Common.Repository;
using GateShift.Common.Repository.Interfaces.DataInterfaces;
using GateShift.Services.GameData.Entities;
using GateShift.Services.GameData.Repositories;
using GateShift.Testing.Mockup.DataLayer;
using GateShift.Testing.Services.GameData.Helpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endregion

namespace GateShift.Testing.Services.GameData.Repositories
{
    /// <summary>
    /// This is a test class for CharacterRepository and is intended
    /// to contain all CharacterRepository Unit Tests
    /// </summary>
    [TestClass]
    public class CharacterRepositoryTest
    {
        #region Fields

        private static EntityConnection _connection;
        private CharacterRepository _repository;

        #endregion

        #region TestContext

        /// <summary>
        /// Gets or sets the test context which provides
        /// information about and functionality for the current test run.
        /// </summary>
        public TestContext TestContext { get; set; }

        #endregion

        #region Additional test attributes

        /// <summary>
        /// Run initialization for all unit tests for this class
        /// </summary>
        /// <param name="testContext">TestContext for this class during initialization</param>
        [ClassInitialize]
        public static void ClassInitialize(TestContext testContext)
        {
            _connection = DBHelper.CreateConnection();
            _connection.Open();
            DBHelper.ClearDatabase();
        }

        /// <summary>
        /// Run cleanup for all unit tests for this class
        /// </summary>
        [ClassCleanup]
        public static void ClassCleanup()
        {
            _connection.Close();
        }

        /// <summary>
        /// Run individual unit test preparation
        /// </summary>
        [TestInitialize]
        public void TestInitialize()
        {
            _repository = new CharacterRepository(_connection);
        }

        /// <summary>
        /// Run individual unit test cleanup
        /// </summary>
        [TestCleanup]
        public void TestCleanup()
        {
            DBHelper.ClearDatabase();
        }

        #endregion

        #region Connection

        /// <summary>
        /// A test for Connection
        /// </summary>
        [TestMethod]
        public void Connection()
        {
            CharacterRepository_Accessor target = new CharacterRepository_Accessor(_connection);
            Assert.AreEqual(_connection, target.Connection);
        }

        #endregion

        #region Save

        /// <summary>
        /// A test for Save
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void Save_Null_ThrowsException()
        {
            _repository.Save(null);
        }

        /// <summary>
        /// A test for Save
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidCastException))]
        public void Save_InvalidData_ThrowsException()
        {
            _repository.Save(new MockCharacter());
        }

        /// <summary>
        /// A test for Save
        /// </summary>
        [TestMethod]
        public void Save_Success()
        {
            _repository.Save(CharacterHelper.CreateCharacter());

            using (EntityDataAdapter dataSource = new EntityDataAdapter(_connection))
            {
                Assert.AreEqual(1, dataSource.Characters.Count());
            }
        }

        #endregion

        #region RetrieveByCharacterName

        /// <summary>
        /// A test for RetrieveByCharacterName
        /// </summary>
        [TestMethod]
        public void RetrieveByCharacterName_Success()
        {
            ICharacterData createdCharacter = CharacterHelper.CreateDBCharacter();

            ICharacterData retrievedCharacter = _repository.RetrieveByCharacterName(createdCharacter.CharacterName);

            Assert.AreEqual(createdCharacter.ID, retrievedCharacter.ID, "ID");
            Assert.AreEqual(createdCharacter.CharacterName, retrievedCharacter.CharacterName, "CharacterName");
        }

        /// <summary>
        /// A test for RetrieveByCharacterName
        /// </summary>
        [TestMethod]
        public void RetrieveByCharacterName_NotFound()
        {
            ICharacterData retrievedCharacter = _repository.RetrieveByCharacterName(CharacterHelper.CreateRandomCharacterName());

            Assert.IsNull(retrievedCharacter, "Character Found");
        }

        /// <summary>
        /// A test for RetrieveByCharacterName
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void RetrieveByCharacterName_NullCharacterName()
        {
            _repository.RetrieveByCharacterName(null);
        }

        #endregion

        #region Retrieve

        #region NoParams

        /// <summary>
        /// A test for Retrieve
        /// </summary>
        [TestMethod]
        public void Retrieve_NoParams_3Items()
        {
            List<ICharacterData> createdCharacters = new List<ICharacterData>
                                                         {
                                                             CharacterHelper.CreateDBCharacter(),
                                                             CharacterHelper.CreateDBCharacter(),
                                                             CharacterHelper.CreateDBCharacter()
                                                         };

            IEnumerable<ICharacterData> retrievedCharacters = _repository.Retrieve();

            Assert.IsNotNull(retrievedCharacters);
            Assert.AreEqual(createdCharacters.Count, retrievedCharacters.Count(), "Count Mismatch");

            foreach (ICharacterData character in retrievedCharacters)
            {
                bool foundItem = false;

                foreach (ICharacterData createdItem in createdCharacters)
                {
                    if (createdItem.ID != character.ID)
                    {
                        continue;
                    }

                    foundItem = true;
                    break;
                }

                if (!foundItem)
                {
                    Assert.Fail("Character not found in expected list");
                }
            }
        }

        /// <summary>
        /// A test for Retrieve
        /// </summary>
        [TestMethod]
        public void Retrieve_NoParams_0Items()
        {
            List<Character> createdCharacters = new List<Character>();

            IEnumerable<ICharacterData> retrievedCharacters = _repository.Retrieve();

            Assert.IsNotNull(retrievedCharacters);
            Assert.AreEqual(createdCharacters.Count, retrievedCharacters.Count(), "Count Mismatch");
        }

        #endregion

        #region ByID

        /// <summary>
        /// A test for Retrieve
        /// </summary>
        [TestMethod]
        public void Retrieve_ByID_Success()
        {
            ICharacterData createdCharacter = CharacterHelper.CreateDBCharacter();

            ICharacterData retrievedCharacter = _repository.Retrieve(createdCharacter.ID);

            Assert.AreEqual(createdCharacter.ID, retrievedCharacter.ID, "ID");
            Assert.AreEqual(createdCharacter.CharacterName, retrievedCharacter.CharacterName, "CharacterName");
        }

        /// <summary>
        /// A test for Retrieve
        /// </summary>
        [TestMethod]
        public void Retrieve_ByID_NoneFound()
        {
            ICharacterData retrievedCharacter = _repository.Retrieve(new Identity(Guid.NewGuid()));

            Assert.IsNull(retrievedCharacter, "Character Found");
        }

        /// <summary>
        /// A test for Retrieve
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidCastException))]
        public void Retrieve_ByID_InvalidIdentity()
        {
            // Characters use ints not guids
            _repository.Retrieve(new Identity(123));
        }

        #endregion

        #endregion

        #region CharacterNameExists

        /// <summary>
        /// A test for CharacterNameExists
        /// </summary>
        [TestMethod]
        public void CharacterNameExists_Success()
        {
            ICharacterData createdCharacter = CharacterHelper.CreateDBCharacter();

            Assert.IsTrue(_repository.CharacterNameExists(createdCharacter.CharacterName, null), "Character Not Found");
        }

        /// <summary>
        /// A test for CharacterNameExists
        /// </summary>
        [TestMethod]
        public void CharacterNameExists_Failure_IgnoreID()
        {
            ICharacterData createdCharacter = CharacterHelper.CreateDBCharacter();

            Assert.IsFalse(_repository.CharacterNameExists(createdCharacter.CharacterName, createdCharacter.ID), "Character Found");
        }

        /// <summary>
        /// A test for CharacterNameExists
        /// </summary>
        [TestMethod]
        public void CharacterNameExists_Failure_DoNotIgnoreID()
        {
            Assert.IsFalse(_repository.CharacterNameExists(CharacterHelper.CreateRandomCharacterName(), null), "Character Found");
        }

        /// <summary>
        /// A test for CharacterNameExists
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CharacterNameExists_Failure_NullCharacterName()
        {
            _repository.CharacterNameExists(null, null);
        }

        /// <summary>
        /// A test for CharacterNameExists
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidCastException))]
        public void CharacterNameExists_InvalidIDType()
        {
            _repository.CharacterNameExists(CharacterHelper.CreateRandomCharacterName(), new Identity(123));
        }

        #endregion

        #region Delete

        /// <summary>
        /// A test for Delete
        /// </summary>
        [TestMethod]
        public void Delete_Success()
        {
            ICharacterData createdCharacter = CharacterHelper.CreateDBCharacter();

            _repository.Delete(createdCharacter);

            using (EntityDataAdapter dataSource = new EntityDataAdapter(_connection))
            {
                Assert.AreEqual(0, dataSource.Characters.Count(), "Characters Found");
            }
        }

        /// <summary>
        /// A test for Delete
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void Delete_NullICharacterData()
        {
            _repository.Delete(null);
        }

        /// <summary>
        /// A test for Delete
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidCastException))]
        public void Delete_InvalidICharacterData()
        {
            _repository.Delete(new MockCharacter());
        }

        /// <summary>
        /// A test for Delete
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void Delete_AlreadyDeleted()
        {
            ICharacterData createdCharacter = CharacterHelper.CreateDBCharacter();

            _repository.Delete(createdCharacter);

            // Try to redelete it
            _repository.Delete(createdCharacter);
        }

        /// <summary>
        /// A test for Delete
        /// </summary>
        [TestMethod]
        [ExpectedException(typeof(InvalidOperationException))]
        public void Delete_DeleteNewCharacter()
        {
            ICharacterData createdCharacter = CharacterHelper.CreateCharacter();

            _repository.Delete(createdCharacter);
        }

        #endregion

        #region Create

        /// <summary>
        /// A test for Create
        /// </summary>
        [TestMethod]
        public void Create()
        {
            ICharacterData character = _repository.Create();

            Assert.IsNotNull(character, "Character is null");
        }

        #endregion
    }
}